import axios from 'axios';
import qs from 'qs';
import 'xgplayer';
import HlsPlayer from 'xgplayer-hls';

import { API, ALLOWED_TYPES, UPLOAD_INFO, CHUNK_SIZE } from './config';
import { formatFileExt } from './utils/tools';

((doc) => {
  //获取进度条元素
  const oProgress = doc.querySelector('#uploadProgress'),
    //获取选择视频元素
    oUploader = doc.querySelector('#videoUploader'),
    //获取上传信息元素
    oInfo = doc.querySelector('#uploadInfo'),
    //获取上传视频按钮元素
    oStartBtn = doc.querySelector('#startBtn'),
    //获取暂停视频按钮元素
    oPauseBtn = doc.querySelector('#pauseBtn');

  let isPaused = true,
    uploadedSize = 0,
    uploadResult = null,
    uploadedFileName = '';

  const init = () => {
    bindEvent();
  };

  function bindEvent() {
    //点击上传视频按钮触发
    oStartBtn.addEventListener('click', uploadVideo, false);
    //点击暂停上传按钮时触发 并传参
    oPauseBtn.addEventListener('click', switchUploader.bind(null, true), false);
  }

  async function uploadVideo() {
    //隐藏 上传视频 按钮
    switchUploader(false);

    /**
     * 选择一个视频mp4文件后点击上传视频按钮后打印
     * console.log(oUploader.files);
     * FileList {
     *   0: {
     *     lastModified: 1649445159768,
     *     lastModifiedDate: Sat Apr 09 2022 03:12:39 GMT+0800 (中国标准时间) {},
     *     name: "study lesson1.mp4",
     *     size: 9536626,
     *     type: "video/mp4",
     *     webkitRelativePath: ""
     *   },
     *   length: 1
     * }
     */

    //解构
    const {
      files: [file]
    } = oUploader;

    /**
     * console.log(file);
     * File {
     *   name: 'study lesson1.mp4',
     *   lastModified: 1649445159768,
     *   lastModifiedDate: Sat Apr 09 2022 03:12:39 GMT+0800 (中国标准时间),
     *   webkitRelativePath: '',
     *   size: 9536626,
     *   name: "study lesson1.mp4",
     *   type: "video/mp4"
     * }
     */

    //如果没有上传文件时
    if (!file) {
      //提示 请先选择文件
      oInfo.innerText = UPLOAD_INFO['NO_FILE'];
      return;
    }

    //没有选择指定的文件类型时
    if (!ALLOWED_TYPES[file.type]) {
      //提示 该文件类型不支持
      oInfo.innerText = UPLOAD_INFO['INVALID_TYPE'];
      return;
    }

    //提取
    const { name, size, type } = file;

    //设置进度条的最大值
    oProgress.max = size;

    //提示 上传中
    oInfo.innerText = UPLOAD_INFO['UPLOADING'];

    //从localStorage中获取上次暂停时的断点信息(对应某个视频名称) 没有时默认为0
    uploadedSize = Number(localStorage.getItem(name || 0));

    //循环切割上传
    //当断点信息的大小小于总视频长度大小时 并且不是暂停时
    while (uploadedSize < size && !isPaused) {
      //继续切割上传
      //备注：file原型上继承了blob对象里的所有方法,包括slice方法
      //slice(从断点大小开始, 断点大小 + 设定的大小 结束)
      const chunk = file.slice(uploadedSize, uploadedSize + CHUNK_SIZE);

      // console.log(chunk);
      //打印了好多 Blob {size: 65536, type: ''} 说明切出来是一个有类型的切片(Blob类型)

      //获取某个新拼接的块名称 时间戳+去除某个视频的.mp4后缀
      const chunkName =
        new Date().getTime() + '_' + formatFileExt(name, ALLOWED_TYPES[type]);

      // console.log(chunkName);
      //1658149708367_study_lesson1

      //创建表单对象
      const formData = createFormData({
        name,
        type,
        size,
        chunkName,
        chunk
      });

      //发送请求并发送formData表单
      try {
        //成功时
        uploadResult = await axios.post(API.UPLOAD_VIDEO, formData);
      } catch (e) {
        //错误时
        //提示 上传失败
        oInfo.innerText = `${UPLOAD_INFO['FAILED']}(${e.message})`;
        return;
      }

      //上传完毕时更新uploadedSize,以便于下次从新的uploadedSize的位置开始切片
      uploadedSize += chunk.size;

      //更新进度条的值(上传读条)
      oProgress.value = uploadedSize;

      //缓存数据 uploadedSize断点信息仅为前端使用
      localStorage.setItem(name, uploadedSize);
    }

    //合并 和 播放视频
    mergeVideo(name, type);
  }

  async function mergeVideo(name, type) {
    //如果不是暂停上传按钮时
    if (!isPaused) {
      oUploader.value = null;
      uploadedFileName = uploadResult.data.filename;
      //提示 转码中
      oInfo.innerText = UPLOAD_INFO['TRANSCODING'];

      //转码
      //qs.stringify序列化post data
      const res = await axios.post(
        API.MERGE_VIDEO,
        qs.stringify({
          filename: uploadedFileName,
          type
        })
      );

      //清除缓存信息
      localStorage.removeItem(name);

      //后端报错误码时
      if (res.data.code === 1006) {
        //提示 上传失败
        oInfo.innerText = `${UPLOAD_INFO['FAILED']}(${res.data.msg})`;
        return;
      }

      //提示 上传成功
      oInfo.innerText = UPLOAD_INFO['SUCCESS'];

      //隐藏 上传视频按钮
      switchUploader(true);

      //生成一个播放器如西瓜
      new HlsPlayer({
        //指定挂载容器
        id: 'videoContainer',
        //后端响应的url播放地址
        url: res.data.videoSrc
      });
    }
  }

  /**
   * 切换是否显示或隐藏上传视频 暂停上传按钮
   * @param {*} bool true显示 false隐藏
   */
  function switchUploader(bool) {
    isPaused = bool;

    //是否显示上传按钮
    oStartBtn.style.display = isPaused ? 'block' : 'none';
    //是否显示暂停上传按钮
    oPauseBtn.style.display = isPaused ? 'none' : 'block';
  }

  /**
   * 组装一个formData对象提供给后端
   * @param {*} name 文件名称
   * @param {*} type 文件类型
   * @param {*} size 文件大小
   * @param {*} chunkName 当前块名称
   * @param {*} chunk 切好之后的blob切片对象
   */
  function createFormData({ name, type, size, chunkName, chunk }) {
    //创建FormData表单对象
    const fd = new FormData();

    //给表单对象插入键名
    fd.append('name', name);
    fd.append('type', type);
    fd.append('size', size);
    fd.append('chunkName', chunkName);
    fd.append('chunk', chunk);

    return fd;
  }

  init();
})(document);
